const path = require('path')
const child_process = require('child_process');
const getM3u8Detail = require('./puppeteer');
const fs = require('fs')
const downloadFile = require('./download')
const inquirer = require('inquirer'); // 咨询用户库
const url = require('url');
var ProgressBar = require("progress");
const request = require('request')

var pageUrl = ''
let tsBaseUrl = ''
let m3u8Domain = ''
let tsArr = null
let tempTsArr = null
let txtContent = ['ffconcat version 1.0']

let tvTotalCount = 0 // 电视剧的总集数
var tvEndNum = 0 // 电视剧下载到多少集 如果两个都填写0，就是从头下到尾
let currentTVNum = 1 // 当前下载到多少集
let startTime = 0 // 计算下载时长

let hasAskNum = false // 是否咨询过下载集数相关信息
let movieTitle = ''

let testCount = 50 // 每集下载多少个ts 测试使用
const tsDir = 'tempTsDir' // 存放临时文件的目录
let downloadType = '' // 全部下载还是选集下载

let bar = null // 显示进度条

let has_key = false // 视频是否有加密

// 多少个ts文件同时下载 线程数
const threadCount = 128
let endCount = 0

// 用户询问
const promptList1 = [{
    type: 'list',
    message: '下载方式:',
    name: 'downloadType',
    choices: [
        "全部下载",
        "选集下载"
    ]
},{
    type: 'input',
    message: `您想从第几集开始看？`,
    name: 'startNum',
    default: "1", // 默认值
    validate: function(val) {
        if(!val.match(/^\d{1,3}$/g)) { // 校验位数
            return "请重新输入3位以下的数字";
        } else if (val > tvTotalCount) {
            return `数字不能大于${tvTotalCount}`;
        }else {
            return true
        }
    },
    when: function (answers) {
        return answers.downloadType === '选集下载'
    }
},{
    type: 'input',
    message: `请输入结束集数：`,
    name: 'endNum',
    validate: function(val) {
        if(!val.match(/^\d{1,3}$/g)) { // 校验位数
            return "请重新输入3位以下的数字";
        } else if (val > tvTotalCount) {
            return `数字不能大于${tvTotalCount}`;
        } else {
            return true
        }
    },
    when: function (answers) {
        return answers.startNum === 0 || answers.startNum
    }
}];
const promptList = [{
    type: 'input',
    message: '请输入页面url',
    name: 'url'
}];

async function execIndex() {
    startTime = Date.now()
    // 每次进来，都先把currentDownload.txt内容遍历一遍，把对应的ts删除掉
    delTsFromCurrentDownloadTxt()

    if (fs.existsSync(path.join(__dirname, tsDir, 'index.txt'))) {
        fs.unlinkSync(path.join(__dirname, tsDir, 'index.txt'))
    }
    const answers = await askUrl()
    pageUrl = answers.url
    let urlPathArr = pageUrl.split('/')
    const htmlName = urlPathArr.pop()
    const htmlNameArr = htmlName.split('-')
    htmlNameArr.pop()
    baseUrl = urlPathArr.join('/') + '/' + htmlNameArr.join('-')
    await getM3u8Detail(false, pageUrl, getRealM3u8)
}

async function getRealM3u8(obj) {
    if (!obj.m3u8) {
        await getM3u8Detail(false, pageUrl, getRealM3u8)
        return
    }
    movieTitle = obj.movieTitle
    if (obj.nums > 1) {
        // 获取电视剧的名称
        tvTotalCount = obj.nums
        // 询问用户从多少集下到多少集，判断是否询问过
        if (!hasAskNum) {
            console.log('这是一个电视剧链接')
            console.log(`当前电视剧的名称是: ${movieTitle}, 总共${obj.nums}集`)
            const answers = await askType()
            console.log('answers:', answers)
           
            downloadType = answers.downloadType
            if (downloadType === '全部下载') {
                currentTVNum = 1
                tvEndNum = tvTotalCount
            } else {
                currentTVNum = answers.startNum * 1
                tvEndNum = answers.endNum * 1
            }
            hasAskNum = true
            // 如果是第一集或者是电影，就往下走
            if (tvTotalCount > 1 && currentTVNum > 1) {
                // 从指定的url重新开始

                let _url = baseUrl + '-' + (currentTVNum - 1) + '.html'
                console.log('page url ---:', _url)
                await getM3u8Detail(false, _url, getRealM3u8)
                return
            }
            // 创建电视剧的总目录
            if (!fs.existsSync(movieTitle)) {
                fs.mkdirSync(movieTitle);
            }
        }
    } else {
        console.log('这是一个电影链接')
    }
    if (tvTotalCount > 1) {
        // 创建第几集的目录
        if (!fs.existsSync(path.join(__dirname, movieTitle))) {
            fs.mkdirSync(path.join(__dirname, movieTitle));
        }
    } else {
        console.log('movieTitle:', movieTitle)
        fs.mkdirSync(path.join(__dirname, movieTitle));
    }
    if (!fs.existsSync(path.join(__dirname, tsDir))) {
        fs.mkdirSync(path.join(__dirname, tsDir));
    }
    let _url = obj.realM3u8Url
    
    if (!obj.realM3u8Url) {
        // 获取m3u8的域名
        const urlObj = url.parse(obj.m3u8Url)
        m3u8Domain = `${urlObj.protocol}//${urlObj.hostname}`
        
        const endText = obj.m3u8[obj.m3u8.length - 1]
        const m3u8Url = obj.m3u8Url
        _url = m3u8Domain + endText
    }
    
    tsBaseUrl = _url.split('/').slice(0, -1).join('/') + '/'
    console.log('tsBaseUrl:', tsBaseUrl)

    // 真是m3u8文件的存放路径
    const realM3u8FilePath = path.join(__dirname, tsDir, 'index.m3u8')

    console.log('_url:', _url)
    //  下载真正的m3u8
    downloadFile(_url, realM3u8FilePath, function () {
        let m3u8 = fs.readFileSync(realM3u8FilePath, 'utf-8');
        let m3u8Arr = []
        let tempArr = m3u8.split('\n')
        tempArr.forEach(item => {
            if (item.endsWith('.ts')) {
                // 如果ts里面含有http，需要更改tsBaseUrl
                if (item.indexOf('http') > -1) {
                    const urlArr = item.split('/')
                    const tsName = urlArr.pop()
                    tsBaseUrl = urlArr.join('/')
                    m3u8Arr.push(tsName)
                } else {
                    m3u8Arr.push(item)
                }
            }
        })
        if (tempArr.some(item => item.indexOf('key.key') > -1)) {
            has_key = true
            console.log('此视频有经过加密~')
            needReWriteFile = true
            let key_url = tsBaseUrl + '/key.key'
            console.log('获取到了key的url：', key_url)
            let stream = fs.createWriteStream('./tempTsDir/key.key');
            request(key_url).pipe(stream).on('close', () => {
                console.log('key 文件下载完成~')
                downloadKeySuccess = true
            });
            reWriteM3u8File();
        }
        tsArr = m3u8Arr
        tempTsArr = [...m3u8Arr]
       
        tsArr.forEach(item => {
            txtContent.push(`file ${item}`)
        })
        fs.writeFileSync(path.join(__dirname, tsDir, "index.txt"), txtContent.join("\n"))
        let text = tvTotalCount > 1 ? `${movieTitle} 第${currentTVNum}集` : movieTitle
        showProgerss(text, m3u8Arr.length)
        downlodTs()
    });
}

// 重写index.m3u8文件
function reWriteM3u8File () {
    let m3u8FileData = fs.readFileSync(path.join(__dirname, tsDir, 'index.m3u8'), 'utf-8')
    const reg_common_text = new RegExp(tsBaseUrl + '/', 'g')
    const content = m3u8FileData.replace(reg_common_text, '')
    fs.writeFileSync(path.join(__dirname, tsDir, 'index.m3u8'), content)
}

function aa() {
    if (!tsArr.length) return
    let ts = tsArr.shift()
    addTextToFile('currentDownload.txt', `\n${ts}`)
    // 如果ts里面含有http，就直接下载ts
    downloadFile(`${tsBaseUrl}/${ts}`, `${tsDir}/${ts}`, function () {
        bar.tick()
        delTextFromFile('currentDownload.txt', ts)
        if (tsArr.length > 0) {
            // 读取currentDownload.txt里面的内容
            // 把当前正在下载的ts文件名删除
            aa()
        } else {
            const fileText = fs.readFileSync(path.join(__dirname, 'currentDownload.txt'), 'utf-8')
            let fileLineArr = fileText.split('\n')
            fileLineArr = fileLineArr.filter(item => item && item.trim())
            if (!fileLineArr.length) {
                has_key ? ts2mp4_key() : ts2mp4()
            }
        }
    })
}


function ts2mp4 () {
     // 使用ffmpeg把ts合并成一个文件
     fs.writeFileSync(path.join(__dirname, tsDir, "index.txt"), txtContent.join("\n"))
     child_process.exec(`ffmpeg -i \'./${tsDir}/index.txt\' -acodec copy -vcodec copy -absf aac_adtstoasc movie.mp4`, {
         maxBuffer: 20000 * 1024, // 默认 200 * 1024
     }, async function (error, stdout, stderr) {
        if (error) {
            console.error("合成失败---", error);
        } else {
            mergeVideoSuccess()
        }
    });
}

function ts2mp4_key () {
    // 使用ffmpeg把ts合并成一个文件
    child_process.exec(`cd tempTsDir && ffmpeg -allowed_extensions ALL -i index.m3u8 -c copy movie.mp4`, async function (error, stdout, stderr) {
        if (error) {
            console.error("合成失败---", error);
        } else {
            mergeVideoSuccess()
        }
    })
}

function mergeVideoSuccess () {
    // 对文件进行改名 并 移动到电视剧的目录中
    const currentName = `${movieTitle}-${currentTVNum}.mp4`
    fs.renameSync(`${tsDir}/movie.mp4`, currentName)
    console.log("合成成功--");
    txtContent = ['ffconcat version 1.0']
    fs.unlinkSync(path.join(__dirname, tsDir, 'index.txt'))
    moveFile(path.join(__dirname, currentName), path.join(__dirname, movieTitle, currentName), async function () {
        if (fs.existsSync(currentName)) {
            fs.unlinkSync(currentName)
        }
        tempTsArr.forEach(item => {
            fs.unlinkSync(path.join(__dirname, tsDir, item))
        })
        fs.unlinkSync(path.join(__dirname, tsDir, 'key.key'))
        tempTsArr = []
        // clearDir(tsDir)
        // 如果是下载电视剧的话，就要看是不是所有都下载完成
        const continueDownload = downloadType === '全部下载' ? currentTVNum < tvTotalCount : currentTVNum < tvEndNum
        if (continueDownload) {
            testCount = 50
            currentTVNum += 1
            let _url = baseUrl + '-' + (currentTVNum - 1) + '.html'
            pageUrl = _url
            downloadKeySuccess = false
            await getM3u8Detail(false, _url, getRealM3u8)
        } else {
            // 如果所有的下载完成，再退出
            console.log(`总用时：${(Date.now() - startTime) / 1000 | 0}s`)
            process.exit()
        }
    })
}

function delTsFromCurrentDownloadTxt () {
    const dirArr = fs.readdirSync(path.join(__dirname))
    if (!dirArr.some(item => item === 'currentDownload.txt')) {
        fs.writeFileSync('currentDownload.txt', '')
        return
    }

    const fileText = fs.readFileSync('currentDownload.txt', 'utf-8')
    if (!fileText) return
    const fileTextArr = fileText.split('\n')
    fileTextArr.forEach(item => {
        if (item) {
            if (fs.existsSync(path.join(__dirname, tsDir, item))) {
                fs.unlinkSync(path.join(__dirname, tsDir, item))
            }
            delTextFromFile('currentDownload.txt', item)
        }
    })
}

// 从文件中删除某个字段
function delTextFromFile (filePath, text) {
    const fileText = fs.readFileSync(filePath, 'utf-8')
    if (!fileText) return
    const fileTextArr = fileText.split('\n')
    if (fileTextArr.includes(text)) {
        const index = fileTextArr.indexOf(text)
        fileTextArr.splice(index, 1)
    }
    const _text = fileTextArr.join('\n')
    fs.writeFileSync(filePath, _text)
}

// 给文件添加字段
function addTextToFile (filePath, text) {
    fs.appendFileSync(filePath, text)
}

function moveFile(fromDir, toDir, callback) {
    var readStream = fs.createReadStream(fromDir);
    var writeStream = fs.createWriteStream(toDir);
    readStream.pipe(writeStream).on('close', callback);
}

// 清空文件夹，只清一层
function clearDir(fileDir) {
    const dirs = fs.readdirSync(fileDir)
    dirs.forEach(item => {
        const fileStat = fs.statSync(path.join(fileDir, item))
        if (fileStat.isFile()) {
            fs.unlinkSync(path.join(fileDir, item))
        }
    })
}

function downlodTs() {
    if (!tsArr.length) return
    for (let i = 0; i < threadCount; i++) {
        aa()
    }
}

// 显示进度条
function showProgerss (text, total) {
    bar = new ProgressBar(`${text}正在下载: :bar, :percent`, { total, width: 20 });
    if (bar.complete) {
        console.log(`\n ${text}下载完成\n`);
    }
}

// 让用户输入url
function askUrl () {
    return new Promise((resolve, reject) => {
        inquirer.prompt(promptList).then(answers => {
            resolve(answers)
        })
    }) 
}

// 让用户选集
function askType () {
    return new Promise((resolve, reject) => {
        inquirer.prompt(promptList1).then(answers => {
            // console.log(answers); // 返回的结果
            resolve(answers)
        })
    }) 
}

execIndex()